[Amazon SageMaker] よく似たパッケージの商品をビルトインアルゴリズムのイメージ分類で判別してみました
1 はじめに
CX事業本部の平内(SIN)です。
前回、よく似たパッケージをAmazon Rekognition(以下、Rekognition)で分類してみました。
各商品50枚の画像(全部で250枚)で、あまりに綺麗に分類できていたので、同じ画像を使って、Amazon SageMaker(以下、SageMaker)のイメージ分類(組み込みアルゴリズム)で同じようなモデルが作成できるかを試してみました。
結論、実力不足で難しかったです。
以下は、今回作成したモデルで推論している様子です。実は、カメラをこれ以上離すと、結構、誤検知が発生してしまい、Rekognitionで作成したモデルより、ぜんぜん性能悪いです。
2 データ
(1) データ
データは、前回のものと同じです。動画(800 * 600 24fps)から切り出した各商品50枚の画像です。
(2) 増幅
各データ50件で学習すると、簡単に収束するのですが、精度が良くなかったため、データの増幅を行いました。
下記のパラメータで、各画像50件から200件に増幅しました。
convertList = [ {"function": saturation, "param": 0.6}, # 彩度 {"function": contrast, "param": 0.8}, # コントラスト {"function": noise, "param": 0.01}, # ごま塩ノイズ ]
全データ: 250件 増幅後データ: 1000件
参考:[Amazon SageMaker] Amazon SageMaker Ground Truth で作成したデータをOpenCVで増幅してみました
(3) イメージ形式データセット
Ground Truth形式となっている上記のデータを、イメージ形式のデータセットに変換してS3にアップロードしています。
全データ: 1000件 EGG (200件) => 160:40 SABA (200件) => 160:40 MEET (200件) => 160:40 HAMBURGER (200件) => 160:40 POTATO (200件) => 160:40 train:800 validation:200
学習用のデータ数は、800件となっています。
参考:[Amazon SageMaker] Amazon SageMaker Ground Truth で作成したデータをイメージ分類で利用可能なイメージ形式に変換してみました
3 学習
学習は、ml.p3.2xlarge(50G)で397秒でした。
設定したパラメータは、以下のとおりです。
early_stopping false epochs 30 learning_rate 0.001 mini_batch_size 32 multi_label 0 num_classes 5 num_layers 152 num_training_samples 800 optimizer sgd precision_dtype float32 use_pretrained_model 1 use_weighted_loss 0
進行の状況です。
epoch Train-accuracy Validation-accuracy ----------------------------------------- 0 0.104 0.208 5 0.826 0.917 10 0.954 0.917 15 1.0 0.951 20 0.998 0.943 25 0.969 0.906 29 1.0 0.979
出来上がったモデルは、208.3MByteとなっていました。
4 確認
デプロイして、動作確認したコードは、以下のとおりです。
import json import datetime import cv2 import numpy as np from boto3.session import Session from PIL import ImageFont, ImageDraw, Image PROFILE = 'developer' END_POINT = 'sampleEndPoint' CLASSES = ['EGG','SABA','MEET','HAMBURGER','POTATO'] NAMES = ['たまごポテトサラダ','さばの塩焼','ミートボール','デミグラスハンバーグ','明太ポテトサラダ'] DEVICE_ID = 0 # Webカメラ HEIGHT = 600 WIDTH = 800 class SageMaker(): def __init__(self, profile, endPoint): self.__end_point = endPoint self.__client = Session(profile_name=profile).client('sagemaker-runtime') def invoke(self, image): data = self.__client.invoke_endpoint( EndpointName=self.__end_point, Body=image, ContentType='image/jpeg' ) return json.loads(data['Body'].read()) def createArea(width, height, w, h, bias): x_1 = int(width/2-w/2) x_2 = int(width/2+w/2) y_1 = int(height/2-h/2) - bias y_2 = int(height/2+h/2) - bias return (x_1, y_1, x_2, y_2) def putText(image, text, point, size, color): font = ImageFont.truetype("./GenShinGothic-Bold.ttf", size) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image = Image.fromarray(image) draw = ImageDraw.Draw(image) draw.text(point, text, color, font) image = np.asarray(image) return cv2.cvtColor(image, cv2.COLOR_RGB2BGR) def main(): cap = cv2.VideoCapture(DEVICE_ID) cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT) fps = cap.get(cv2.CAP_PROP_FPS) width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) print("FPS:{} WIDTH:{} HEIGHT:{}".format(fps, width, height)) (x_1, y_1, x_2, y_2) = createArea(width, height, 400, 400, 50) sageMake = SageMaker(PROFILE, END_POINT) while True: # カメラ画像取得 _, frame = cap.read() if(frame is None): continue img = frame[y_1: y_2, x_1: x_2] # 推論 _, jpg = cv2.imencode('.jpg', img) results = sageMake.invoke(jpg.tostring()) probabilitys = {} for i, result in enumerate(results): probabilitys[CLASSES[i]] = result probabilitys = sorted(probabilitys.items(), key = lambda x:x[1], reverse=True) (name, probability) = probabilitys[0] # 結果表示 text = "{} {}".format(NAMES[CLASSES.index(name)], probability) frame = putText(frame, text, (20, int(height) - 120), 60, (255, 255, 255)) # 対象範囲の枠表示 frame = cv2.rectangle(frame, (x_1, y_1), (x_2, y_2), (155, 155, 155), 1) # フレーム表示 cv2.imshow('frame', frame) cv2.waitKey(1) cap.release() cv2.destroyAllWindows() main()
5 最後に
今回は、よく似たパッケージの商品でイメージ分類モデルを作成してみました。
正直、Rekognitionの精度には、全然追いついてませんが、Rekognitionの内部で、どのように処理されているのか(画像増幅やパラメータの調整など)に思いを馳せながら、1日色々試していました。
体感として、ある程度の精度までは、簡単に出るのですが、ある一線を超えると精度を上げるのが非常に難しい印象です。頑張って勉強します。